#include <QtCore/QCoreApplication>
#include <QPluginLoader>
#include <QDir>
#include <QFile>

#include <iostream>

#include "../plugin.h"
#include "../data/fileplugin.h"
#include "../data/reg3dvolumedata.h"
#include "../contree/contreeconstructor3d.h"
#include "../contree/augmentedctree.h"
#include "../contree/ctreecontourextractor.h"
#include "../math/timer.h"
#include "../mact/dctconstructor.h"
#include "../mact/dualgraph.h"

using namespace PBVP;

int main(int argc, char *argv[])
{

	QCoreApplication a(argc, argv);
	//return a.exec();
	
	// load plugins
	QDir pluginsDir = QDir(a.applicationDirPath());
	std::cout << pluginsDir.absolutePath().toStdString() << std::endl;
	if (pluginsDir.dirName().toLower() == "debug" 
		|| pluginsDir.dirName().toLower() == "release") {
			pluginsDir.cdUp();
	}
	pluginsDir.cdUp();
	pluginsDir.cd("plugins");

	QStringList pluginEntries = pluginsDir.entryList(QDir::Files);

	FilePluginInterface* rawivPlugin;
	FilePluginInterface* rawPlugin;
	FilePluginInterface* rawncPlugin;

	// check additional potential plugin path if necessary
	if(pluginEntries.size() == 0) {
		pluginsDir = QDir(a.applicationDirPath());
		pluginsDir.cd("plugins");
		pluginEntries = pluginsDir.entryList(QDir::Files);
	}

	foreach (QString fileName, pluginEntries) {
		if (fileName.contains("rawiv"))
		{
			QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
			QObject *plugin = loader.instance();
			if (plugin) {
				rawivPlugin = qobject_cast<FilePluginInterface *>(plugin);
				if (rawivPlugin) {
					rawivPlugin->initialize(NULL);
					std::cout << rawivPlugin->description().toStdString() << std::endl;		
				} 
			}
		} else if (fileName.contains("rawfile"))
		{
			QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
			QObject *plugin = loader.instance();
			if (plugin) {
				rawPlugin = qobject_cast<FilePluginInterface *>(plugin);
				if (rawPlugin) {
					rawPlugin->initialize(NULL);
					std::cout << rawPlugin->description().toStdString() << std::endl;		
				} 
			}
		} else if (fileName.contains("rawncfile"))
		{
			QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
			QObject *plugin = loader.instance();
			if (plugin)
			{
				rawncPlugin = qobject_cast<FilePluginInterface *>(plugin);
				if (rawncPlugin) 
				{
					rawncPlugin->initialize(NULL);
					std::cout << rawncPlugin->description().toStdString() << std::endl;
				}
			}
		}
	}
	Timer timer;
	timer.getCurrentTime();
	std::cout << "processing file " << argv[1] << std::endl;
	Reg3DVolumeData *pReg3Data = dynamic_cast<Reg3DVolumeData *>(rawivPlugin->loadFile(argv[1]));
	AugmentedContourTree *acTree = new AugmentedContourTree();

	char cTreeFile[256];
	sprintf(cTreeFile, "%s.ctr", argv[1]);
	if (!acTree->loadFile(cTreeFile))
	{
		ConTreeConstructorReg3D *construcCT = new ConTreeConstructorReg3D(pReg3Data);
		delete acTree;
		acTree = construcCT->getAugmentedContourTree(); 
		delete construcCT;
		acTree->saveFile(cTreeFile);
	}
	
	CTreeContourExtractor* pConExtractor = new CTreeContourExtractor(pReg3Data, acTree);
	//for (int i = 0; i < cutArcs->size(); i++)
	//{
	//	SuperArc & arc = (*cutArcs)[i];
	//	int startId = pConExtractor->getStartTetra((*cutArcs)[i], 1);
	//	std::cout << i << "th start Tetra = " << startId << std::endl; 
	//}
	//acTree->getBettiNumbers(1);
	GeometryData *pSurf = pConExtractor->extractContour(pReg3Data, 1.5);
	rawPlugin->saveFile(pSurf, "tmp.raw");
	rawncPlugin->saveFile(pSurf, "tmp.rawnc");

	return 0;

	DCTConstructor *dctContruct = new DCTConstructor(pReg3Data, acTree);
	DualGraph *dcTree = dctContruct->buildDualGraph(1.7, 4, 16);
	char dcTreeFile[256];
	sprintf(dcTreeFile, "%s.dct", argv[1]);
	dcTree->saveFile(dcTreeFile);
	std::cout << "Elapsed time = " << timer.getElapsedTime() << std::endl;
	delete pSurf;
	delete pConExtractor;
	delete acTree;
	delete pReg3Data;
}